package com.psak.cudaphrasal.server.service.inputfile;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

import com.psak.cudaphrasal.server.service.cache.WordHashCache;

/**
 * Uslugi zwiazane z zarzadaniem plikiem wejsciowym.
 * 
 * @author piotrs10
 * 
 */
public class InputFileManagementService {

	private static int BUFFER_SIZE = 8192; // 8 kb
	private static int CACHE_REALLOCATION_SIZE = 64; // co ile realokowac
														// tablice z cache'ami
	private String fileToProcess;

	private WordHashCache wordHashCache;
	private List<String> stopWordCache = new ArrayList<String>(
			CACHE_REALLOCATION_SIZE);

	/**
	 * Inicjalizacja uslugi
	 * 
	 * @throws InputFileManagementServiceException
	 */
	public void init() throws InputFileManagementServiceException {
		loadStopWords();
	}

	/**
	 * Laduje z pliku tzw. stop words
	 * 
	 * @throws InputFileManagementServiceException
	 */
	private void loadStopWords() throws InputFileManagementServiceException {
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new InputStreamReader(this.getClass()
					.getResourceAsStream("/stopwords-500.txt")), BUFFER_SIZE);
			String line = reader.readLine();
			while (line != null) {
				stopWordCache.add(line.trim());
				line = reader.readLine();
			}
		} catch (IOException e) {
			throw new InputFileManagementServiceException(
					"Blad odczytu z pliku wejsciowego", e);
		} finally {
			if (reader != null) {
				try {
					reader.close();
				} catch (IOException e) {
					throw new InputFileManagementServiceException(
							"Nie mozna zamknac pliku", e);
				}
			}
		}

	}

	/**
	 * Zamienia zawartosc pliku na liste hash'y slow.
	 * 
	 * @param inputFile
	 *            Plik wejsciowy.
	 * @return Lista z hashami.
	 * @throws InputFileManagementServiceException
	 */
	public List<Long> convertFileToWordHashList()
			throws InputFileManagementServiceException {
		List<Long> outputList = new ArrayList<Long>();
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(
					new FileReader(new File(fileToProcess)), BUFFER_SIZE);
			String currentLine = null;
			currentLine = reader.readLine();
			while (currentLine != null) {
				extractWordsAndComputeHash(currentLine, outputList);
				currentLine = reader.readLine();
			}
		} catch (FileNotFoundException e) {
			throw new InputFileManagementServiceException(
					"Plik wejsciowy nie istnieje", e);
		} catch (IOException e) {
			throw new InputFileManagementServiceException(
					"Blad odczytu z pliku wejsciowego", e);
		} finally {
			if (reader != null) {
				try {
					reader.close();
				} catch (IOException e) {
					throw new InputFileManagementServiceException(
							"Nie mozna zamknac pliku", e);
				}
			}
		}
		return outputList;
	}

	private void extractWordsAndComputeHash(String currentLine,
			List<Long> outputList) {
		StringTokenizer tokenizer = new StringTokenizer(currentLine, " ");
		while (tokenizer.hasMoreTokens()) {
			// obliczamy hash kolejnego slow
			String currentWord = tokenizer.nextToken();
			// usuwamy znaki, ktore nie sa literami
			currentWord = deleteNonLiteralChars(currentWord);
			// sprawdzamy czy jest stopword
			if (!isStopWord(currentWord)) {
				long hash = (long) currentWord.hashCode();
				// dodajemy hash ze slowem do cache'a
				wordHashCache.put(hash, currentWord);
				outputList.add(hash);
			}
		}
	}

	/**
	 * Sprawdza czy slowo nie jest stop word.
	 * 
	 * @param currentWord
	 *            Slowo.
	 * @return true - dla stop word, false dla nie stop word
	 */
	private boolean isStopWord(String currentWord) {
		for (String stopWord : stopWordCache) {
			if (stopWord.equals(currentWord)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Usuwamy wszystkie znaki, które nie sa literami.
	 * 
	 * @param currentWord
	 *            Slowo.
	 * @return Przetworzony string.
	 */
	private String deleteNonLiteralChars(String currentWord) {
		StringBuilder resultBuffer = new StringBuilder();
		char[] currentWordChars = currentWord.toCharArray();
		for (char currentChar : currentWordChars) {
			if (Character.isLetter(currentChar)) {
				resultBuffer.append(currentChar);
			}
		}
		return resultBuffer.toString();
	}

	public void setWordHashCache(WordHashCache wordHashCache) {
		this.wordHashCache = wordHashCache;
	}

	public void setFileToProcess(String fileToProcess) {
		this.fileToProcess = fileToProcess;
	}

}
